package com.oracle.sbdb.bo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.oracle.sbdb.dao.BugInfoDao;
import com.oracle.sbdb.model.BugInfo;
import com.oracle.sbdb.servlet.model.BugInformation;
import com.oracle.sbdb.servlet.model.BugUpdates;
import com.oracle.sbdb.util.BugTypeUtil;
import com.oracle.sbdb.util.GenericPortUtil;
import com.oracle.sbdb.util.OSUtil;
import com.oracle.sbdb.util.SeverityUtil;
import com.oracle.sbdb.util.SimilarityUtils;
import com.oracle.sbdb.util.StatusUtil;
import com.oracle.sbdb.util.StopsUtils;

public class BugInfoBo {
	public static BugInfoBo INSTANCE = new BugInfoBo();
	private static EngineerBo engineerBo = EngineerBo.INSTANCE;
	private static UpdatesBo updatesBo = UpdatesBo.INSTANCE;
	private static ProductBo productBo = ProductBo.INSTANCE;
	private static ComponentBo componentBo = ComponentBo.INSTANCE;

	private static BugInfoDao bugInfoDao = new BugInfoDao();

	private static Map<Integer, BugInfo> bugMap = new HashMap<Integer, BugInfo>();
	private static Map<Integer, List<Integer>> employeeMap = new HashMap<Integer, List<Integer>>();

	private BugInfoBo() {
	};

	public BugInformation selectbyID(int bugId) {
		BugInfo bugInfo = null;
		if (bugMap.containsKey(bugId)) {
			bugInfo = bugMap.get(bugId);
		} else {
			bugInfo = bugInfoDao.selectbyId(bugId);
			bugMap.put(bugId, bugInfo);
		}

		BugInformation res = bugInfo == null ? null
				: convert2BugInformation(bugInfo);
		return res;
	}

	public BugInfo selectBugInfobyID(int bugId) {
		BugInfo bugInfo = null;
		if (bugMap.containsKey(bugId)) {
			bugInfo = bugMap.get(bugId);
		} else {
			bugInfo = bugInfoDao.selectbyId(bugId);
			bugMap.put(bugId, bugInfo);
		}

		return bugInfo;
	}

	public List<BugInformation> selectbyKeyPhrase(String key) {
		List<BugInformation> res = null;

		List<String> phraseList = null;
		
		if (key != null) {
			
			String[] phraseArray = key.split(" ");
			
			if (phraseArray != null) {
				
				phraseList = new ArrayList<String>();
				
				for (String phrase : phraseArray) {
					String ripePhrase = phrase.trim();
					
					if (ripePhrase.length() > 0) {
						phraseList.add(ripePhrase);
					}
				}
			}
		}

		if (phraseList != null && phraseList.size() > 0) {
			String keyPhrase = phraseList.get(0);
			
			List<BugInfo> rawList = bugInfoDao.selectbyKeyPhrase(keyPhrase);
			
			if (rawList != null) {
				for (BugInfo bugInfo : rawList) {
					String bugSubject = bugInfo.getBug_subject();
					boolean match = true;
					
					for (String phrase : phraseList) {
						if (!bugSubject.contains(phrase)) {
							match = false;
						}
					}
					if (match) {
						BugInformation bugInformation = convert2BugInformation(bugInfo);
						
						if (bugInformation != null) {
							if (res == null) {
								res = new ArrayList<BugInformation>();
							}
							bugMap.put(bugInfo.getBug_id(), bugInfo);
							res.add(bugInformation);
						}
					}
				}
			}
		}

		return res;
	}
	
	public List<BugInformation> selectRelatedBug(int bugId) {
		List<BugInformation> res = null;
		BugInfo bugInfo = selectBugInfobyID(bugId);
		
		if(bugInfo == null){
			return res;
		}
		
		List<BugInfo> scBugList = bugInfoDao.selectbyComponentId(bugInfo.getComponent_id());
		
		if(scBugList == null){
			return res;
		}
		
		TreeMap<Double, BugInfo> relatedBugs = new TreeMap<Double, BugInfo>();
		List<String> origWordsList = StopsUtils.filterSentence(bugInfo.getBug_subject());
		for(BugInfo elem : scBugList){
			if(elem.getBug_id() == bugId){
				continue;
			}
			List<String> compareWordsList = StopsUtils.filterSentence(elem.getBug_subject());
			double similarity = SimilarityUtils.getSimilarity(origWordsList, compareWordsList);
			relatedBugs.put(similarity, elem);
			if(relatedBugs.size() > 5){
				relatedBugs.pollLastEntry();
			}
		}
		
		if(relatedBugs.size() > 0){
			res = new ArrayList<BugInformation>();
			for(BugInfo relatedBug : relatedBugs.values()){
				if(!bugMap.containsKey(relatedBug.getBug_id())){
					bugMap.put(relatedBug.getBug_id(), relatedBug);
				}
				BugInformation bugInformation = convert2BugInformation(relatedBug);
				if(bugInformation != null){
					res.add(bugInformation);
				}
			}
		}
		
		return res;
	}
	
	public List<BugInformation> selectGroupBug(int employeeId) {
		int departmentId = EngineerBo.INSTANCE.getDepartmentIDbyId(employeeId);
		
		if (departmentId == -1) {
			return null;
		}
		List<Integer> engineerIDList = EngineerBo.INSTANCE
				.selectEngineerIdbyDepartmentId(departmentId);
		
		if (engineerIDList == null || engineerIDList.size() == 0) {
			return null;
		}
		List<BugInformation> res = new ArrayList<BugInformation>();
		for (int engineerID : engineerIDList) {
			List<BugInformation> tempList = selectbyEmployeeID(engineerID);
			if (tempList != null) {
				res.addAll(tempList);
			}
		}
		Collections.sort(res, new Comparator<BugInformation>() {
			public int compare(BugInformation o1, BugInformation o2) {
				if (o1.getBugID() < o2.getBugID()) {
					return 1;
				} else {
					return -1;
				}
			}
		});
		return res;

	}

	public void updateBug(BugInformation bugInformation) {
		BugInfo bugInfo = convert2BugInfo(bugInformation);
		bugInfoDao.update(bugInfo);
	}

	public List<BugInformation> selectbyEmployeeID(int employeeId) {
		List<BugInformation> res = new ArrayList<BugInformation>();

		if (employeeMap.containsKey(employeeId)) {
			List<Integer> bugIdList = employeeMap.get(employeeId);

			for (int bugId : bugIdList) {
				BugInformation bugInfo = selectbyID(bugId);
				res.add(bugInfo);
			}
		} else {
			List<BugInfo> bugInfoList = bugInfoDao
					.selectbyEmployeeId(employeeId);

			List<Integer> bugIdList = new ArrayList<Integer>();

			for (BugInfo bugInfo : bugInfoList) {
				bugIdList.add(bugInfo.getBug_id());
				if (!bugMap.containsKey(bugInfo.getBug_id())) {
					bugMap.put(bugInfo.getBug_id(), bugInfo);
				}
				BugInformation bugInformation = convert2BugInformation(bugInfo);
				if(bugInformation != null){
					res.add(bugInformation);
				}
			}

			employeeMap.put(employeeId, bugIdList);
		}

		return res;
	}

	private BugInformation convert2BugInformation(BugInfo bugInfo) {
		int bugID = bugInfo.getBug_id();
		String subject = bugInfo.getBug_subject();
		int productID = bugInfo.getProduct_id();
		int componentID = bugInfo.getComponent_id();
		int assigneeID = bugInfo.getAssignee_id();
		int supportID = bugInfo.getSupport_id();
		String customer = bugInfo.getCustomer();
		int statusID = bugInfo.getStatus();
		int severityID = bugInfo.getSeverity();
		int bugTypeID = bugInfo.getBug_type();
		char genAndPrtID = bugInfo.getGen_prt();
		int osID = bugInfo.getBug_os_id();
		String OSRelease = bugInfo.getBug_os_release();

		String product = productBo.getProductNamebyID(productID);
		String component = componentBo.getComponentNamebyID(componentID);
		String assignee = engineerBo.getEngineerGIdbyId(assigneeID);
		String support = engineerBo.getEngineerGIdbyId(supportID);
		String status = StatusUtil.getStatus(statusID);
		String severity = SeverityUtil.getSeverity(severityID);
		String bugType = BugTypeUtil.getBugType(bugTypeID);
		String genAndPrt = GenericPortUtil.getGenericPort(genAndPrtID);
		String OS = OSUtil.getOSName(osID);

		List<BugUpdates> updatesList = updatesBo.selectbyUpdatesId(bugID);

		BugInformation res = new BugInformation(bugID, subject, product,
				component, assignee, support, customer, status, severity,
				bugType, genAndPrt, OS, OSRelease);
		res.setUpdatesList(updatesList);

		return res;
	}

	private BugInfo convert2BugInfo(BugInformation bugInformation) {
		int bugId = bugInformation.getBugID();
		BugInfo res = selectBugInfobyID(bugId);

		if (res == null) {
			return res;
		}

		String subject = bugInformation.getSubject();
		String assigneeIdString = bugInformation.getAssignee();
		String statusString = bugInformation.getStatus();
		String severityString = bugInformation.getSeverity();
		String bugOSIdString = bugInformation.getOS();
		String bugOSRelease = bugInformation.getOSRelease();

		int assigneeId = engineerBo.getEngineerIdbyGId(assigneeIdString);
		int status = StatusUtil.getStatusId(statusString);
		int severity = SeverityUtil.getSeverityNumber(severityString);
		int bugOSId = OSUtil.getOSNameId(bugOSIdString);

		if (!subject.equals(res.getBug_subject())) {
			res.setBug_subject(subject);
		}

		if (assigneeId != res.getAssignee_id()) {
			res.setAssignee_id(assigneeId);
		}

		if (status != res.getStatus()) {
			res.setStatus(status);
		}

		if (severity != res.getSeverity()) {
			res.setSeverity(severity);
		}

		if (bugOSId != res.getBug_os_id()) {
			res.setBug_os_id(bugOSId);
		}

		if (!bugOSRelease.equals(res.getBug_os_release())) {
			res.setBug_os_release(bugOSRelease);
		}

		return res;
	}
}
